package com.jiatuxueyuan.the4.remoteio;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;

import java.util.List;

/**
 * 因为TCP存在粘包、分包的情况，当前socket中的字节流很可能不是一个完整的modbus tcp报文，有可能是一部分的tcp报文，也有可能是2个、3个多个tcp报文粘在一起的，所以我们要把它们准确的分割开。
 *
 * <p>ByteToMessageDecoder这个父类，本身也继承了ChannelInboundHandlerAdapter，它内部有一个ByteBuf的缓冲区，用来缓存所有收到的字节，只要从socket中收到字节流，就会被放进去，这样的话，
 * 客户端发过来的所有字节都会被累加着放进去，至于如何解析，就是自己的事情了。</p>
 *
 * <p>下面的4行注释非常重要！</p>
 * 1. ByteToMessageDecoder is an implementation of ChannelInboundHandler which makes it easy to deal with the fragmentation issue.
 * 2. ByteToMessageDecoder calls the decode() method with an internally maintained cumulative buffer whenever new data is received.
 * 3. decode() can decide to add nothing to out when there is not enough data in the cumulative buffer. ByteToMessageDecoder will call decode() again
 *      when there is more data received.
 * 4. If decode() adds an object to out, it means the decoder decoded a message successfully. ByteToMessageDecoder will discard the read part of the cumulative buffer.
 *      Please remember that you don't need to decode multiple messages. ByteToMessageDecoder will keep calling the decode() method until it adds nothing to out.
 */
public class ZlanModbusTcpDecoder extends ByteToMessageDecoder {

    /**
     * 一旦socket中收到远端发过来的字节流，decode方法就会被调用，我们需要自行判断当前收到的字节流够不够
     *
     * @param ctx
     * @param in
     * @param out
     * @throws Exception
     */
    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        if(in.readableBytes() < 6) {
            return;
        }
        out.add(in.readBytes(6));//读6个字节出去，一旦读走了6个字节，ByteToMessageDecoder它自己会从它的内部缓冲区中去掉读走的6个字节，不然的话，下次岂不是重复处理这6个字节了。
    }
}
